#include<iostream>
#include<stdio.h>
#include<string>
#include<sstream>
#include<fstream>
#include<utmp.h>
#include<utime.h>
#include<time.h>
#include<fcntl.h>
#include<unistd.h>
#include<sys/stat.h>
#include<sys/wait.h>
#include<dirent.h>
#include<vector>
using namespace std;

struct ipv4地址{
    unsigned char ip[4];
};
struct ipv6地址{
    unsigned short ip[8];
};
struct 登陆记录
{
    int ip46;
    ipv4地址 ipv4;
    ipv6地址 ipv6;
    tm 时间;
    int 尝试次数;
};

struct ip列表{
    int ip46;
    int 编号;
    ipv4地址 ipv4;
    ipv6地址 ipv6;
    tm 时间;
};

vector<登陆记录> 登陆记录链表;

vector<ip列表> 白名单;
vector<ip列表> 黑名单;
vector<ip列表> 当前封禁;

int 检查时间间隔 = 3600;
int 检查过去登陆时间 = 43200;
int 最大检查ip数 = 100000;
int 过去登陆时间内限制尝试次数 = 20;
int 封禁时长 = 86400;
string 守护日志地址 = "/var/log/watcherlog.log";
string 登陆日志地址 = "/var/log/btmp";
string 防火墙命令 = "iptable";
fstream 守护日志;
int 守护日志状态 = 0;

int 判断ipv46(char a[]);
ipv6地址 字符串到地址转换6(char ip[]);
ipv4地址 字符串到地址转换4(char ip[]);
int 判断ipv46(string ip);
ipv6地址 字符串到地址转换6(string ip);
ipv4地址 字符串到地址转换4(string ip);
int 登陆记录链表查找ip(登陆记录 ip);
void 加入登陆记录链表(int ip46, char ip[], tm 尝试时间);
void 读取配置文件();
int 比较时间(tm tm1, tm tm2);
int 地址链表查找ip(vector<ip列表> *表头, ip列表 ip);
void 加入地址链表(vector<ip列表> *表头, ip列表 插入元素);
void 读取白名单();
void 读取黑名单();
void 守护日志输出(string line);
string ip地址转字符串(ip列表 ip);
void 封禁ip();
void 解封ip();

class 防火墙操作
{
public:
    vector<ip列表> 启动禁止列表;
    int 防火墙模式;
    防火墙操作()
    {
        启动禁止列表.clear();
        if (防火墙命令 == "iptable")
        {
            防火墙模式 = 0;
        }
        else
        {
            防火墙模式 = 1;
        }
    }
    void 构建禁止列表()
    {
        if (防火墙模式 == 0)
        {
            FILE *防火墙输出;
            char 输出[1024];
            stringstream ss;
            string st, st1;
            int t;
            int n = 0;
            防火墙输出 = popen("iptables -L -n --line-number", "r");
            int status;
            wait(&status);
            do
            {
                if (fgets(输出, 1024, 防火墙输出) != NULL)
                {
                    ss.str("");
                    ss.clear();
                    ss << 输出;
                    st = ss.str();
                    if (st.find("Chain", 0) != string::npos)
                    {
                        if (st.find("FORWARD", 0) != string::npos || st.find("OUTPUT", 0) != string::npos)
                        {
                            break;
                        }
                    }
                    else
                    {
                        if (st.find("REJECT", 0) != string::npos || st.find("DROP", 0) != string::npos)
                        {
                            ss >> t;
                            ss >> st1;
                            ss >> st1;
                            ss >> st1;
                            ss >> st1;
                            st1 = st1.substr(0, st1.find("/", 0));
                            if (判断ipv46(st1) == 4)
                            {
                                启动禁止列表.push_back({4, t, 字符串到地址转换4(st1), {0}, {0}});
                            }
                            else if (判断ipv46(st1) == 6)
                            {
                                启动禁止列表.push_back({6, t, {0}, 字符串到地址转换6(st1), {0}});
                            }
                        }
                    }
                }
                else
                {
                    break;
                }
                n = n + 1;
            } while (n < 最大检查ip数);
            pclose(防火墙输出);
        }
        else if (防火墙模式 == 1)
        {
            FILE *防火墙输出;
            char 输出[1024];
            stringstream ss;
            string st;
            int n = 0;
            防火墙输出 = popen("firewall-cmd --list-rich-rules", "r");
            int status;
            wait(&status);
            do
            {
                if (fgets(输出, 1024, 防火墙输出) != NULL)
                {
                    ss.str("");
                    ss.clear();
                    ss << 输出;
                    st = ss.str();
                    if (st.find("rule", 0) != string::npos)
                    {
                        if ((st.find("reject", 0) != string::npos || st.find("drop", 0) != string::npos) && st.find("family=", 0) != string::npos && st.find("source address=", 0) != string::npos)
                        {
                            if (st[st.find("family=", 0) + 11] == '4')
                            {
                                启动禁止列表.push_back({4, 0, 字符串到地址转换4(st.substr(st.find("source address=", 0) + 16, st.find("\"", st.find("source address=", 0) + 16) - (st.find("source address=", 0) + 16))), {0}, {0}});
                            }
                            else if (st[st.find("family=", 0) + 11] == '6')
                            {
                                启动禁止列表.push_back({4, 0, {0}, 字符串到地址转换6(st.substr(st.find("source address=", 0) + 16, st.find("\"", st.find("source address=", 0) + 16) - (st.find("source address=", 0) + 16))), {0}});
                            }
                        }
                    }
                }
                else
                {
                    break;
                }
                n = n + 1;
            } while (n < 最大检查ip数);
            pclose(防火墙输出);
        }
    }
    void 清除列表()
    {
        启动禁止列表.clear();
    }
    int 查找ip(ip列表 ip)
    {
        int n = 0;
        do
        {
            if (n >= 启动禁止列表.size())
            {
                return -1;
            }
            if (ip.ip46 == 启动禁止列表[n].ip46)
            {
                if (ip.ip46 == 4)
                {
                    if (ip.ipv4.ip[0] == 启动禁止列表[n].ipv4.ip[0] && ip.ipv4.ip[1] == 启动禁止列表[n].ipv4.ip[1] && ip.ipv4.ip[2] == 启动禁止列表[n].ipv4.ip[2] && ip.ipv4.ip[3] == 启动禁止列表[n].ipv4.ip[3])
                    {
                        return n;
                    }
                }
                else if (ip.ip46 == 6)
                {
                    if (ip.ipv6.ip[0] == 启动禁止列表[n].ipv6.ip[0] && ip.ipv6.ip[1] == 启动禁止列表[n].ipv6.ip[1] && ip.ipv6.ip[2] == 启动禁止列表[n].ipv6.ip[2] && ip.ipv6.ip[3] == 启动禁止列表[n].ipv6.ip[3] && ip.ipv6.ip[4] == 启动禁止列表[n].ipv6.ip[4] && ip.ipv6.ip[5] == 启动禁止列表[n].ipv6.ip[5] && ip.ipv6.ip[6] == 启动禁止列表[n].ipv6.ip[6] && ip.ipv6.ip[7] == 启动禁止列表[n].ipv6.ip[7])
                    {
                        return n;
                    }
                }
            }
            n = n + 1;
        } while (n < 启动禁止列表.size());
        return -1;
    }
    int 添加禁止ip(ip列表 ip)
    {
        if (查找ip(ip) >= 0)
        {
            return 1;
        }
        if (防火墙模式 == 0)
        {
            FILE *防火墙输出;
            char 输出[1024];
            stringstream ss;
            string st, st1;
            ss.str("");
            ss.clear();
            if (ip.ip46 == 4)
            {
                ss << (int)ip.ipv4.ip[0] << '.' << (int)ip.ipv4.ip[1] << '.' << (int)ip.ipv4.ip[2] << '.' << (int)ip.ipv4.ip[3];
                st1 = ss.str();
            }
            else if (ip.ip46 == 6)
            {
                ss << hex << (int)ip.ipv6.ip[0] << ':' << (int)ip.ipv6.ip[1] << ':' << (int)ip.ipv6.ip[2] << ':' << (int)ip.ipv6.ip[3] << ':' << (int)ip.ipv6.ip[3] << ':' << (int)ip.ipv6.ip[3] << ':' << (int)ip.ipv6.ip[4] << ':' << (int)ip.ipv6.ip[5] << ':' << (int)ip.ipv6.ip[6] << ':' << (int)ip.ipv6.ip[7] << dec;
                st1 = ss.str();
            }
            else
            {
                return 0;
            }
            st = "iptables -I INPUT -s" + st1 + " -j DROP";
            防火墙输出 = popen(st.c_str(), "r");
            int status;
            wait(&status);
            if (fgets(输出, 1024, 防火墙输出) != NULL)
            {
                ss.str("");
                ss.clear();
                ss << 输出;
                st = ss.str();
                守护日志输出("iptables输出：" + st);
                if (st.length() <= 2)
                {
                    启动禁止列表.push_back(ip);
                    守护日志输出("iptables输出：");
                    return 1;
                }
                else if (st.find("BAD", 0) != string::npos || st.find("Bad", 0) != string::npos || st.find("bad", 0) != string::npos || st.find("err", 0) != string::npos || st.find("ERR", 0) != string::npos || st.find("Err", 0) != string::npos || st.find("fail", 0) != string::npos || st.find("FAIL", 0) != string::npos || st.find("Fail", 0) != string::npos)
                {

                    守护日志输出("iptables输出：");
                    return 0;
                }
            }
            else
            {
                启动禁止列表.push_back(ip);
                守护日志输出("iptables输出：");
                return 1;
            }
            pclose(防火墙输出);
        }
        else if (防火墙模式 == 1)
        {
            FILE *防火墙输出;
            char 输出[1024];
            stringstream ss;
            string st, st1;
            ss.str("");
            ss.clear();
            if (ip.ip46 == 4)
            {
                ss << (int)ip.ipv4.ip[0] << '.' << (int)ip.ipv4.ip[1] << '.' << (int)ip.ipv4.ip[2] << '.' << (int)ip.ipv4.ip[3];
                st1 = ss.str();
            }
            else if (ip.ip46 == 6)
            {
                ss << hex << (int)ip.ipv6.ip[0] << ':' << (int)ip.ipv6.ip[1] << ':' << (int)ip.ipv6.ip[2] << ':' << (int)ip.ipv6.ip[3] << ':' << (int)ip.ipv6.ip[3] << ':' << (int)ip.ipv6.ip[3] << ':' << (int)ip.ipv6.ip[4] << ':' << (int)ip.ipv6.ip[5] << ':' << (int)ip.ipv6.ip[6] << ':' << (int)ip.ipv6.ip[7] << dec;
                st1 = ss.str();
            }
            else
            {
                return 0;
            }
            st = "firewall-cmd --add-rich-rule='rule family=ipv" + (ip.ip46==4?(string)"4":(string)"6") + (string) " source address=\"" + st1 + "\" drop'";
            防火墙输出 = popen(st.c_str(), "r");
            int status;
            wait(&status);
            if (fgets(输出, 1024, 防火墙输出) != NULL)
            {
                ss.str("");
                ss.clear();
                ss << 输出;
                st = ss.str();
                守护日志输出("firewalld输出：" + st);
                if (st.length() <= 2 || st.find("success", 0) != string::npos || st.find("Success", 0) != string::npos || st.find("SUCCESS", 0) != string::npos)
                {
                    启动禁止列表.push_back(ip);
                    守护日志输出("firewalld输出：");
                    return 1;
                }
                else if (st.find("BAD", 0) != string::npos || st.find("Bad", 0) != string::npos || st.find("bad", 0) != string::npos || st.find("err", 0) != string::npos || st.find("ERR", 0) != string::npos || st.find("Err", 0) != string::npos || st.find("fail", 0) != string::npos || st.find("FAIL", 0) != string::npos || st.find("Fail", 0) != string::npos)
                {
                    守护日志输出("firewalld输出：");
                    return 0;
                }
            }
            else
            {
                启动禁止列表.push_back(ip);
                守护日志输出("firewalld输出：");
                return 1;
            }
            pclose(防火墙输出);
        }
        else
        {
            return 0;
        }
        return 0;
    }
    int 删除禁止ip(ip列表 ip)
    {
        int n = 0;
        n = 查找ip(ip);
        if (n >= 0)
        {
            if (防火墙模式 == 0)
            {
                FILE *防火墙输出;
                char 输出[1024];
                stringstream ss;
                string st, st1;
                ss.str("");
                ss.clear();
                if (ip.ip46 == 4)
                {
                    ss << (int)ip.ipv4.ip[0] << '.' << (int)ip.ipv4.ip[1] << '.' << (int)ip.ipv4.ip[2] << '.' << (int)ip.ipv4.ip[3];
                    st1 = ss.str();
                }
                else if (ip.ip46 == 6)
                {
                    ss << hex << (int)ip.ipv6.ip[0] << ':' << (int)ip.ipv6.ip[1] << ':' << (int)ip.ipv6.ip[2] << ':' << (int)ip.ipv6.ip[3] << ':' << (int)ip.ipv6.ip[3] << ':' << (int)ip.ipv6.ip[3] << ':' << (int)ip.ipv6.ip[4] << ':' << (int)ip.ipv6.ip[5] << ':' << (int)ip.ipv6.ip[6] << ':' << (int)ip.ipv6.ip[7] << dec;
                    st1 = ss.str();
                }
                else
                {
                    return 0;
                }
                st = "iptables -D INPUT -s" + st1 + " -j DROP";
                防火墙输出 = popen(st.c_str(), "r");
                int status;
                wait(&status);
                if (fgets(输出, 1024, 防火墙输出) != NULL)
                {
                    ss.str("");
                    ss.clear();
                    ss << 输出;
                    st = ss.str();
                    守护日志输出("iptables输出：" + st);
                    if (st.length() <= 2)
                    {
                        启动禁止列表.erase(启动禁止列表.begin() + n);
                        守护日志输出("iptables输出：");
                        return 1;
                    }
                    else if (st.find("BAD", 0) != string::npos || st.find("Bad", 0) != string::npos || st.find("bad", 0) != string::npos || st.find("err", 0) != string::npos || st.find("ERR", 0) != string::npos || st.find("Err", 0) != string::npos || st.find("fail", 0) != string::npos || st.find("FAIL", 0) != string::npos || st.find("Fail", 0) != string::npos)
                    {
                        守护日志输出("iptables输出：");
                        return 0;
                    }
                }
                else
                {
                    启动禁止列表.erase(启动禁止列表.begin() + n);
                    守护日志输出("iptables输出：");
                    return 1;
                }
                pclose(防火墙输出);
            }
            else if (防火墙模式 == 1)
            {
                FILE *防火墙输出;
                char 输出[1024];
                stringstream ss;
                string st, st1;
                ss.str("");
                ss.clear();
                if (ip.ip46 == 4)
                {
                    ss << (int)ip.ipv4.ip[0] << '.' << (int)ip.ipv4.ip[1] << '.' << (int)ip.ipv4.ip[2] << '.' << (int)ip.ipv4.ip[3];
                    st1 = ss.str();
                }
                else if (ip.ip46 == 6)
                {
                    ss << hex << (int)ip.ipv6.ip[0] << ':' << (int)ip.ipv6.ip[1] << ':' << (int)ip.ipv6.ip[2] << ':' << (int)ip.ipv6.ip[3] << ':' << (int)ip.ipv6.ip[3] << ':' << (int)ip.ipv6.ip[3] << ':' << (int)ip.ipv6.ip[4] << ':' << (int)ip.ipv6.ip[5] << ':' << (int)ip.ipv6.ip[6] << ':' << (int)ip.ipv6.ip[7] << dec;
                    st1 = ss.str();
                }
                else
                {
                    return 0;
                }
                st = "firewall-cmd --remove-rich-rule='rule family=ipv" + (ip.ip46 == 4 ? (string) "4" : (string) "6") + (string) " source address=\"" + st1 + "\" drop'";
                防火墙输出 = popen(st.c_str(), "r");
                int status;
                wait(&status);
                if (fgets(输出, 1024, 防火墙输出) != NULL)
                {
                    ss.str("");
                    ss.clear();
                    ss << 输出;
                    st = ss.str();
                    守护日志输出("firewalld输出：" + st);
                    if (st.length() <= 2 || st.find("success", 0) != string::npos || st.find("Success", 0) != string::npos || st.find("SUCCESS", 0) != string::npos)
                    {
                        启动禁止列表.erase(启动禁止列表.begin() + n);
                        守护日志输出("firewalld输出：");
                        return 1;
                    }
                    else if (st.find("BAD", 0) != string::npos || st.find("Bad", 0) != string::npos || st.find("bad", 0) != string::npos || st.find("err", 0) != string::npos || st.find("ERR", 0) != string::npos || st.find("Err", 0) != string::npos || st.find("fail", 0) != string::npos || st.find("FAIL", 0) != string::npos || st.find("Fail", 0) != string::npos)
                    {
                        守护日志输出("firewalld输出：");
                        return 0;
                    }
                }
                else
                {
                    启动禁止列表.erase(启动禁止列表.begin() + n);
                    守护日志输出("firewalld输出：");
                    return 1;
                }
                pclose(防火墙输出);
            }
            return 0;
        }
        else
        {
            return 1;
        }
    }
    ~防火墙操作()
    {
        启动禁止列表.clear();
    }
};

防火墙操作 防火墙;

int main()
{
    读取配置文件();
    int 日志文件;
    utmp 登陆尝试;
    struct stat64 日志文件状态;
    守护日志.open(守护日志地址.c_str(), ios_base::app);
    time_t 现在时间;
    timespec 上次查看时间;
    上次查看时间.tv_nsec = 0;
    上次查看时间.tv_sec = 0;
    time(&现在时间);
    tm 时间;
    时间=*(localtime(&现在时间));
    if (守护日志.good()){
        守护日志状态 = 1;
        守护日志 << "守护程序启动，时间：" << 时间.tm_year + 1900 << "年" << 时间.tm_mon + 1 << "月" << 时间.tm_mday << "日" << 时间.tm_hour << ":" << 时间.tm_min << ":" << 时间.tm_sec << endl;
        守护日志 << "检查时间间隔=" << 检查时间间隔 << endl;
        守护日志 << "检查过去登陆时间=" << 检查过去登陆时间 << endl;
        守护日志 << "最大检查ip数=" << 最大检查ip数 << endl;
        守护日志 << "过去登陆时间内限制尝试次数=" << 过去登陆时间内限制尝试次数 << endl;
        守护日志 << "封禁时长=" << 封禁时长 << endl;
        守护日志 << "守护日志地址=" << 守护日志地址 << endl;
        守护日志 << "登陆日志地址=" << 登陆日志地址 << endl;
        守护日志 << "防火墙命令=" << 防火墙命令 << endl;
    }
    守护日志.close();
    防火墙.构建禁止列表();
    白名单.clear();
    黑名单.clear();
    读取白名单();
    读取黑名单();
    当前封禁.clear();
    int n = 0;
    do{
        if(n>=黑名单.size()){
            break;
        }
        else{
            if(地址链表查找ip(&白名单,黑名单[n])>=0){
                ;
            }
            else{
                黑名单[n].时间 = 时间;
                当前封禁.push_back(黑名单[n]);
                守护日志输出(ip地址转字符串(黑名单[n]) + "将根据黑名单加入防火墙。");
                防火墙.添加禁止ip(黑名单[n]);
            }
        }
        n = n + 1;
    } while (n < 黑名单.size());
    do
    {
        stat64(登陆日志地址.c_str(), &日志文件状态);
        if(日志文件状态.st_mtim.tv_sec>上次查看时间.tv_sec||(日志文件状态.st_mtim.tv_sec==上次查看时间.tv_sec&&日志文件状态.st_mtim.tv_nsec>上次查看时间.tv_nsec)){
            上次查看时间 = 日志文件状态.st_mtim;
            日志文件 = open(登陆日志地址.c_str(), O_RDONLY);
            time(&现在时间);
            时间 = *(localtime(&现在时间));
            if (日志文件 == -1)
            {
                守护日志输出("日志文件读取错误。");
            }
            else{
                while(read(日志文件,&登陆尝试,sizeof(登陆尝试))==sizeof(登陆尝试)){
                    if (登陆尝试.ut_type == LOGIN_PROCESS){
                        if ((现在时间 - 登陆尝试.ut_tv.tv_sec) < 检查过去登陆时间)
                        {
                            switch(判断ipv46(登陆尝试.ut_host)){
                                case 0:
                                    break;
                                case 4:
                                    加入登陆记录链表(4, 登陆尝试.ut_host,*localtime((time_t*)&登陆尝试.ut_tv.tv_sec));
                                    break;
                                case 6:
                                    加入登陆记录链表(6, 登陆尝试.ut_host, *localtime((time_t *)&登陆尝试.ut_tv.tv_sec));
                                    break;
                                default:
                                    break;
                                }
                        }
                    }
                }
                守护日志输出("日志文件读取完成。");
                封禁ip();
                解封ip();
            }
            close(日志文件);
            登陆记录链表.clear();
        }
        sleep(检查时间间隔);
    } while (1);
    return 0;
}

void 守护日志输出(string line){
    if(守护日志状态==0){
        return;
    }
    time_t 现在时间;
    time(&现在时间);
    tm 时间;
    时间 = *(localtime(&现在时间));
    守护日志.open(守护日志地址.c_str(), ios_base::app);
    if (守护日志.good())
    {
        守护日志 << 时间.tm_year + 1900 << "年" << 时间.tm_mon + 1 << "月" << 时间.tm_mday << "日" << 时间.tm_hour << ":" << 时间.tm_min << ":" << 时间.tm_sec << ":" << line << endl;
    }
    守护日志.close();
}

void 封禁ip(){
    int n = 0;
    int n1 = 0;
    time_t 现在时间;
    time(&现在时间);
    tm 时间;
    时间 = *(localtime(&现在时间));
    do
    {
        if(n>=登陆记录链表.size()){
            break;
        }
        else{
            if(登陆记录链表[n].尝试次数 >= 过去登陆时间内限制尝试次数){
            n1 = 地址链表查找ip(&当前封禁, {登陆记录链表[n].ip46, 0, 登陆记录链表[n].ipv4, 登陆记录链表[n].ipv6, 登陆记录链表[n].时间});
            if(n1>=0){
                if(比较时间(当前封禁[n1].时间,登陆记录链表[n].时间)<0){
                    守护日志输出(ip地址转字符串({登陆记录链表[n].ip46, 0, 登陆记录链表[n].ipv4, 登陆记录链表[n].ipv6, 登陆记录链表[n].时间}) + "已经封禁，检查防火墙设置。");
                    当前封禁[n1].时间 = 时间;
                }
                else{
                    ;
                }
            }
            else{
                if (地址链表查找ip(&白名单, {登陆记录链表[n].ip46, 0, 登陆记录链表[n].ipv4, 登陆记录链表[n].ipv6, 登陆记录链表[n].时间})>=0){
                    ;
                }
                else{    
                    加入地址链表(&当前封禁, {登陆记录链表[n].ip46, 0, 登陆记录链表[n].ipv4, 登陆记录链表[n].ipv6, 时间});
                    守护日志输出(ip地址转字符串({登陆记录链表[n].ip46, 0, 登陆记录链表[n].ipv4, 登陆记录链表[n].ipv6, 登陆记录链表[n].时间}) + "将写入防火墙。");
                    防火墙.添加禁止ip({登陆记录链表[n].ip46, 0, 登陆记录链表[n].ipv4, 登陆记录链表[n].ipv6, 时间});
                }
            }
        }
        }
        n = n + 1;
    } while (n < 登陆记录链表.size());
}

void 解封ip(){
    int n = 0;
    time_t 现在时间;
    time(&现在时间);
    tm 时间;
    时间 = *(localtime(&现在时间));
    do{
        if(n>=当前封禁.size()){
            break;
        }
        else{
            if(比较时间(时间,当前封禁[n].时间)>封禁时长){
                if(地址链表查找ip(&黑名单,当前封禁[n])>=0){
                    ;
                }
                else{
                    守护日志输出(ip地址转字符串(当前封禁[n]) + "将从防火墙中删除，允许通过。");
                    防火墙.删除禁止ip(当前封禁[n]);
                    当前封禁.erase(当前封禁.begin() + n);
                }
            }
        }
        n = n + 1;
    } while (n < 当前封禁.size());
}

string ip地址转字符串(ip列表 ip){
    stringstream ss;
    string st;
    if(ip.ip46==4){
        ss.str("");
        ss.clear();
        ss << (int)ip.ipv4.ip[0] << '.' << (int)ip.ipv4.ip[1] << '.' << (int)ip.ipv4.ip[2] << '.' << (int)ip.ipv4.ip[3];
        st = ss.str();
        return st;
    }
    else if(ip.ip46==6){
        ss.str("");
        ss.clear();
        ss << hex << ip.ipv6.ip[0] << ':' << ip.ipv6.ip[1] << ':' << ip.ipv6.ip[2] << ':' << ip.ipv6.ip[3] << ':' << ip.ipv6.ip[4] << ':' << ip.ipv6.ip[5] << ':' << ip.ipv6.ip[6] << ':' << ip.ipv6.ip[7] << dec;
        st = ss.str();
        return st;
    }
    else{
        return ip.ip46 != 6 ? "0.0.0.0" : "0:0:0:0:0:0:0:0";
    }
}

int 判断ipv46(char a[] ){
    int ip46 = 0;
    int n = 0;
    do
    {
        if(a[n]==':'){
            ip46 = 6;
            break;
        }
        else if(a[n]=='.'){
            ip46 = 4;
            break;
        }
        else if(a[n]==0){
            break;
        }
        n = n + 1;
    } while (n < 256);
    return ip46;
}

ipv4地址 字符串到地址转换4(char ip[]){
    ipv4地址 ipr = {{0, 0, 0, 0}};
    int n = 0;
    char t = 0;
    do{
        if(ip[n]>='0'&&ip[n]<='9'){
            t = t * 10 + ip[n] - '0';
        }
        else{
            break;
        }
        n = n + 1;
    } while (n < 32);
    if(ip[n]=='.'){
        ipr.ip[0] = t;
        t = 0;
        n = n + 1;
    }
    else{
        return ipr;
    }
    do
    {
        if (ip[n] >= '0' && ip[n] <= '9')
        {
            t = t * 10 + ip[n] - '0';
        }
        else
        {
            break;
        }
        n = n + 1;
    } while (n < 32);
    if (ip[n] == '.')
    {
        ipr.ip[1] = t;
        t = 0;
        n = n + 1;
    }
    else
    {
        return ipr;
    }
    do
    {
        if (ip[n] >= '0' && ip[n] <= '9')
        {
            t = t * 10 + ip[n] - '0';
        }
        else
        {
            break;
        }
        n = n + 1;
    } while (n < 32);
    if (ip[n] == '.')
    {
        ipr.ip[2] = t;
        t = 0;
        n = n + 1;
    }
    else
    {
        return ipr;
    }
    do
    {
        if (ip[n] >= '0' && ip[n] <= '9')
        {
            t = t * 10 + ip[n] - '0';
        }
        else
        {
            break;
        }
        n = n + 1;
    } while (n < 32);
    ipr.ip[3] = t;
    return ipr;
}

ipv6地址 字符串到地址转换6(char ip[]){
    ipv6地址 ipr = {{0, 0, 0, 0, 0, 0, 0, 0}};
    int n = 0;
    int n1 = 0;
    int n2 = 0;
    int n3 = 0;
    short t = 0;
    do{
        do
        {
            if (ip[n] >= '0' && ip[n] <= '9')
            {
                t = t * 16 + ip[n]-'0';
            }
            else if(ip[n]>='a'&&ip[n]<='f'){
                t = t * 16 + ip[n] - 'a' + 10;
            }
            else if (ip[n] >= 'A' && ip[n] <= 'F')
            {
                t = t * 16 + ip[n] - 'A' + 10;
            }
            else
            {
                break;
            }
            n = n + 1;
        } while (n < 48);
        if(ip[n]==':'||n1==7){
            ipr.ip[n1] = t;
            if(n1!=7&&t==0&&n>0&&ip[n-1]==':'){
                n2 = n + 1;
                n3 = 0;
                do{
                    if(ip[n2]==':'){
                        n3 = n3 + 1;
                    }
                    n2 = n2 + 1;
                } while (n2 < 48);
                n1 = 6 - n3;
            }
            t = 0;
            n = n + 1;
        }
        else{
            return ipr;
        }
        n1 = n1 + 1;
    } while (n1 < 8);
    return ipr;
}

int 登陆记录链表查找ip(登陆记录 ip){
    int n = 0;
    do{
        if(n>=登陆记录链表.size()){
            return -1;
        }
        if(登陆记录链表[n].ip46==ip.ip46){
            if(ip.ip46==4){
                if (登陆记录链表[n].ipv4.ip[0] == ip.ipv4.ip[0] && 登陆记录链表[n].ipv4.ip[1] == ip.ipv4.ip[1] && 登陆记录链表[n].ipv4.ip[2] == ip.ipv4.ip[2] && 登陆记录链表[n].ipv4.ip[3] == ip.ipv4.ip[3]){
                    return n;
                }
            }
            else if(ip.ip46==6){
                if (登陆记录链表[n].ipv6.ip[0] == ip.ipv6.ip[0] && 登陆记录链表[n].ipv6.ip[1] == ip.ipv6.ip[1] && 登陆记录链表[n].ipv6.ip[2] == ip.ipv6.ip[2] && 登陆记录链表[n].ipv6.ip[3] == ip.ipv6.ip[3] && 登陆记录链表[n].ipv6.ip[4] == ip.ipv6.ip[4] && 登陆记录链表[n].ipv6.ip[5] == ip.ipv6.ip[5] && 登陆记录链表[n].ipv6.ip[6] == ip.ipv6.ip[6] && 登陆记录链表[n].ipv6.ip[7] == ip.ipv6.ip[7])
                {
                    return n;
                }
            }
        }
        n = n + 1;
    } while (n < 登陆记录链表.size());
    return -1;
}

void 加入登陆记录链表(int ip46, char ip[],tm 尝试时间)
{
    登陆记录 记录;
    记录.ip46 = ip46;
    if(ip46==4){
        记录.ipv4 = 字符串到地址转换4(ip);
    }
    else if(ip46==6){
        记录.ipv6 = 字符串到地址转换6(ip);
    }
    else{
        return;
    }
    记录.时间 = 尝试时间;
    记录.尝试次数 = 1;
    int n = 登陆记录链表查找ip(记录);
    if (n >= 0)
    {
        登陆记录链表[n].尝试次数 = 登陆记录链表[n].尝试次数 + 1;
        登陆记录链表[n].时间 = 尝试时间;
    }
    else{
        登陆记录链表.push_back(记录);
    }
    return;

}

void 读取配置文件(){
    fstream 配置文件;
    string 配置行;
    string 配置名;
    string 配置值;
    stringstream sst;
    int en = 0;
    int 整数值;
    配置文件.open("/etc/serverwatcher/serverwatcher.config", ios_base::in);
    do{
    if(配置文件.good()){
        getline(配置文件, 配置行);
        en = 配置行.find("=", 0) == string::npos ? -1 : 配置行.find("=", 0);
        if (en == -1 || 配置行[0] == '#' || 配置行[0] == '/' || 配置行[0] == ';')
        {
            ;
        }
        else{
            配置名 = 配置行.substr(0, en);
            配置值 = 配置行.substr(en + 1, 配置行.length() - en - 1);
            if(配置名!=""&&配置值!=""){
                if (配置名 == "检查时间间隔"){
                    sst.str("");
                    sst.clear();
                    sst << 配置值;
                    sst >> 整数值;
                    if(整数值>60){
                        检查时间间隔 = 整数值;
                    }
                }
                else if (配置名 == "检查过去登陆时间"){
                    sst.str("");
                    sst.clear();
                    sst << 配置值;
                    sst >> 整数值;
                    if (整数值 > 60)
                    {
                        检查过去登陆时间 = 整数值;
                    }
                }
                else if (配置名 == "最大检查ip数"){
                    sst.str("");
                    sst.clear();
                    sst << 配置值;
                    sst >> 整数值;
                    if (整数值 > 10)
                    {
                        最大检查ip数 = 整数值;
                    }
                }
                else if (配置名 == "过去登陆时间内限制尝试次数")
                {
                    sst.str("");
                    sst.clear();
                    sst << 配置值;
                    sst >> 整数值;
                    if (整数值 > 2)
                    {
                        过去登陆时间内限制尝试次数 = 整数值;
                    }
                }
                else if (配置名 == "封禁时长")
                {
                    sst.str("");
                    sst.clear();
                    sst << 配置值;
                    sst >> 整数值;
                    if (整数值 > 3600)
                    {
                        封禁时长 = 整数值;
                    }
                }
                else if (配置名 == "守护日志地址")
                {
                    if(配置值[0]=='/'){
                        if(opendir(配置值.substr(0, 配置值.find_last_of("/")).c_str())==NULL){
                            ;
                        }
                        else{
                            守护日志地址 = 配置值;
                        }
                    }
                }
                else if (配置名 == "登陆日志地址")
                {
                    if (配置值[0] == '/')
                    {
                        if (opendir(配置值.substr(0, 配置值.find_last_of("/")).c_str()) == NULL)
                        {
                            ;
                        }
                        else
                        {
                            登陆日志地址 = 配置值;
                        }
                    }
                }
                else if (配置名 == "防火墙命令")
                {
                    if (配置值 == "Iptable" || 配置值 == "Iptables" || 配置值 == "iptable" || 配置值 == "iptables" || 配置值 == "IPTABLE" || 配置值 == "IPTABLES")
                    {
                        防火墙命令 = "iptable";
                    }
                    else if (配置值 == "firewall" || 配置值 == "firewalld" || 配置值 == "FIREWALL" || 配置值 == "FIREWALLD" || 配置值 == "Firewall" || 配置值 == "Firewalld"){
                        防火墙命令 = "firewall";
                    }
                }
            }
        }

    }
    } while (配置文件.good());
    配置文件.close();
    return;
}

int 判断ipv46(string ip){
    char t[256] = {0};
    ip.copy(t, ip.length(), 0);
    return 判断ipv46(t);
}

ipv6地址 字符串到地址转换6(string ip)
{
    char t[256] = {0};
    ip.copy(t, ip.length(), 0);
    return 字符串到地址转换6(t);
}

ipv4地址 字符串到地址转换4(string ip){
    char t[256] = {0};
    ip.copy(t, ip.length(), 0);
    return 字符串到地址转换4(t);
}

void 读取白名单(){
    fstream 白名单文件;
    string 白名单行;
    白名单文件.open("/etc/serverwatcher/whitelist", ios_base::in);
    do{
        if(白名单文件.good()){
            getline(白名单文件, 白名单行);
            if (白名单行.length()<256&&((白名单行[0] >= '0' && 白名单行[0] <= '9') || (白名单行[0] >= 'a' && 白名单行[0] <= 'f') || (白名单行[0] >= 'A' && 白名单行[0] <= 'F') || (白名单行[0] == ':')))
            {
                if(判断ipv46(白名单行)==6){
                    ipv6地址 ip6 = 字符串到地址转换6(白名单行.c_str());
                    加入地址链表(&白名单, {6, 0, {0}, ip6, {0}});
                }
                else if (判断ipv46(白名单行) == 4){
                    ipv4地址 ip4 = 字符串到地址转换4(白名单行.c_str());
                    加入地址链表(&白名单, {4, 0, ip4, {0}, {0}});
                }
            }
        }
    } while (白名单文件.good());
    白名单文件.close();
    加入地址链表(&白名单, {4, 0, {0, 0, 0, 0}, {0}, {0}});
    加入地址链表(&白名单, {4, 0, {127, 0, 0, 1}, {0}, {0}});
    加入地址链表(&白名单, {6, 0, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 1}, {0}});
    加入地址链表(&白名单, {6, 0, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}, {0}});
    return;
}

void 读取黑名单()
{
    fstream 黑名单文件;
    string 黑名单行;
    黑名单文件.open("/etc/serverwatcher/blacklist", ios_base::in);
    do
    {
        if (黑名单文件.good())
        {
            getline(黑名单文件, 黑名单行);
            if (黑名单行.length() < 256 && ((黑名单行[0] >= '0' && 黑名单行[0] <= '9') || (黑名单行[0] >= 'a' && 黑名单行[0] <= 'f') || (黑名单行[0] >= 'A' && 黑名单行[0] <= 'F') || (黑名单行[0] == ':')))
            {
                if (判断ipv46(黑名单行) == 6)
                {
                    ipv6地址 ip6 = 字符串到地址转换6(黑名单行.c_str());
                    加入地址链表(&黑名单, {6, 0, {0}, ip6, {0}});
                }
                else if (判断ipv46(黑名单行) == 4)
                {
                    ipv4地址 ip4 = 字符串到地址转换4(黑名单行.c_str());
                    加入地址链表(&黑名单, {4, 0, ip4, {0}, {0}});
                }
            }
        }
    } while (黑名单文件.good());
    黑名单文件.close();
    return;
}

int 地址链表查找ip(vector<ip列表> *表头, ip列表 ip)
{
    int n = 0;
    do
    {
        if (n >= (*表头).size())
        {
            return -1;
        }
        if ((*表头)[n].ip46 == ip.ip46)
        {
            if (ip.ip46 == 4)
            {
                if ((*表头)[n].ipv4.ip[0] == ip.ipv4.ip[0] && (*表头)[n].ipv4.ip[1] == ip.ipv4.ip[1] && (*表头)[n].ipv4.ip[2] == ip.ipv4.ip[2] && (*表头)[n].ipv4.ip[3] == ip.ipv4.ip[3])
                {
                    return n;
                }
            }
            else if (ip.ip46 == 6)
            {
                if ((*表头)[n].ipv6.ip[0] == ip.ipv6.ip[0] && (*表头)[n].ipv6.ip[1] == ip.ipv6.ip[1] && (*表头)[n].ipv6.ip[2] == ip.ipv6.ip[2] && (*表头)[n].ipv6.ip[3] == ip.ipv6.ip[3] && (*表头)[n].ipv6.ip[4] == ip.ipv6.ip[4] && (*表头)[n].ipv6.ip[5] == ip.ipv6.ip[5] && (*表头)[n].ipv6.ip[6] == ip.ipv6.ip[6] && (*表头)[n].ipv6.ip[7] == ip.ipv6.ip[7])
                {
                    return n;
                }
            }
        }
        n = n + 1;
    } while (n < (*表头).size());
    return -1;
}

void 加入地址链表(vector<ip列表> *表头,ip列表 插入元素){
    int n = 0;
    n = 地址链表查找ip(表头,插入元素);
    if (n>=0){
        return;
    }
    else{
        (*表头).push_back(插入元素);
    }
    return;
}

int 比较时间(tm tm1,tm tm2){
    return mktime(&tm1) - mktime(&tm2);
}

